﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.IO;
using System.Web.Compilation;
using MvcEngine.Core.Utils;
using MvcEngine.Mvc.View.Skin;
using System.Web;

namespace MvcEngine.Mvc.View.ViewEngine
{
    public class MvcEngineWebFormView : WebFormView
    {
        #region Private fields
        private string controllerName;
        private string moduleName;
        #endregion

        #region Public properties
        public ISkinEngine SkinEngine { get; set; }
        #endregion

        #region Public Constructors
        public MvcEngineWebFormView(string viewPath)
            : base(viewPath) { }

        public MvcEngineWebFormView(string viewPath, string masterPath)
            : base(viewPath, masterPath) { }
        #endregion

        #region Public Methods
        public override void Render(ViewContext viewContext, TextWriter writer)
        {
            if (viewContext == null)
            {
                throw new ArgumentNullException("viewContext");
            }

            controllerName = viewContext.Controller.ControllerContext.RouteData.GetRequiredString("controller");

#warning change this make it testable
            //moduleName = HttpContext.Current.Items["CurrentModule"] as string; //ModuleManager.Current.GetModuleName(viewContext.Controller.ControllerContext.Controller.GetType().Assembly.GetName().Name);
            moduleName = viewContext.Controller.ControllerContext.RouteData.Values["moduleName"] as string;

            object viewInstance = BuildManager.CreateInstanceFromVirtualPath(ViewPath, typeof(object));
            if (viewInstance == null)
            {
                throw new InvalidOperationException(
                    string.Format(
                        "An instance of the view '{0}' could not be created.",
                        ViewPath
                        )
                    );
            }

            ViewPage viewPage = viewInstance as ViewPage;
            if (viewPage != null)
            {
                if (!string.IsNullOrEmpty(MasterPath) && !string.IsNullOrEmpty(viewPage.MasterLocation))
                {
                    viewPage.MasterLocation = MasterPath;
                }

                viewPage.ViewData = viewContext.ViewData;
                viewPage.PreInit += viewPage_PreInit;

                viewPage.RenderView(viewContext);

                return;
            }
            else
            {
                ViewUserControl control = viewInstance as ViewUserControl;
                if (control == null)
                {
#warning add logical message
                    throw new InvalidOperationException();
                }
                this.RenderViewUserControl(viewContext, control);
            }
        }
        #endregion


        private void RenderViewUserControl(ViewContext context, ViewUserControl control)
        {
            if (!string.IsNullOrEmpty(this.MasterPath))
            {
#warning add logical message
                throw new InvalidOperationException();
            }
            control.ViewData = context.ViewData;
            control.RenderView(context);
        }

        #region Private event handlers
        private void viewPage_PreInit(object sender, EventArgs e)
        {
            ViewPage viewPage = (ViewPage)sender;

            var areaName = viewPage.ViewContext.RouteData.DataTokens["area"].ToString();

            if (!string.IsNullOrEmpty(viewPage.MasterPageFile))
            {
                string[] locationsSearched = new string[0];
                string masterName = Path.GetFileNameWithoutExtension(viewPage.MasterPageFile);

                viewPage.MasterPageFile = SkinEngine.FindMasterPath(masterName, areaName, controllerName, moduleName, out locationsSearched);

                if (string.IsNullOrEmpty(viewPage.MasterPageFile))
                {
                    throw new InvalidOperationException(
                        string.Format(
                            "The master page '{0}' could not be found. The following locations were searched:\r\n{1}",
                            masterName,
                            string.Join("\r\n", locationsSearched)
                            )
                        );
                }

#warning Fix this for nested master pages
                if (!string.IsNullOrEmpty(viewPage.Master.MasterPageFile))
                {
                    masterName = Path.GetFileNameWithoutExtension(viewPage.Master.MasterPageFile);
                    viewPage.Master.MasterPageFile = SkinEngine.FindMasterPath(masterName, areaName, controllerName, moduleName, out locationsSearched);

                    if (string.IsNullOrEmpty(viewPage.Master.MasterPageFile))
                    {
                        throw new InvalidOperationException(
                            string.Format(
                                "The master page '{0}' could not be found. The following locations were searched:\r\n{1}",
                                masterName,
                                string.Join("\r\n", locationsSearched)
                                )
                            );
                    }
                }

            }
        }
        #endregion
    }
}
